package com.codedancer.campus.chat.api.websocket;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.SpringContextUtils;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.enums.ChatMessageContentType;
import com.codedancer.campus.mapper.ChatMessageMapper;
import com.codedancer.campus.mapper.ChatRoomMapper;
import com.codedancer.campus.mapper.ContactAdminChatMessageMapper;
import com.codedancer.campus.mapper.UserMapper;
import com.codedancer.campus.po.ChatMessage;
import com.codedancer.campus.po.ChatRoom;
import com.codedancer.campus.po.ContactAdminChatMessage;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE,
    RequestMethod.PUT}, maxAge = 3600)
@Api(value = "联系管理员websockerApi", description = "联系管理员websockerApi", tags = "联系管理员websockerApi")
@ServerEndpoint(value = "/contactAdmin/websocket/one2one/{sendId}/{roomId}")
@Slf4j
public class ContactAdminWebSocketEndPoint {

    // 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount;
    //实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key为用户标识
    private static final Map<String, ContactAdminWebSocketEndPoint> connections = new ConcurrentHashMap<>();
    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private String roomId;

    /**
     * 连接建立成功调用的方法
     *
     * @param sendId
     * @param roomId
     */
    @OnOpen
    public void onOpen(@PathParam(value = "sendId") String sendId,
                       @PathParam(value = "roomId") String roomId, Session session) {
        this.session = session;
        this.roomId = roomId;
        connections.put(sendId, this);
        addOnlineCount();
        log.info("sendId：{}，roomId：{}", sendId, roomId);
        log.info("有新连接加入！新用户：{}，当前在线人数为：{}", sendId, getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) throws IOException {
        log.info("收到消息：{}", message);
        send(message);
    }

    /**
     * 获取在线人数
     *
     * @return
     */
    private static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 增加在线人数
     */
    private static synchronized void addOnlineCount() {
        ContactAdminWebSocketEndPoint.onlineCount++;
    }

    /**
     * 发送信息到客户端展示
     *
     * @param message
     */
    private void send(String message) throws IOException {
        ContactAdminChatMessageMapper contactAdminChatMessageMapper = SpringContextUtils.getBean(ContactAdminChatMessageMapper.class);
        UserMapper userMapper = SpringContextUtils.getBean(UserMapper.class);
        JSONObject jsonObject = JSONUtil.parseObj(message);
        // 消息内容
        String content = jsonObject.get("content").toString();
        // 消息发送者
        String sendUserUuid = jsonObject.get("sendUserUuid").toString();
        // 消息接收者
        String receiveUserUuid = jsonObject.get("receiveUserUuid").toString();
        // roomId
        String roomId = jsonObject.get("roomId").toString();
        // 内容类型
        Integer contentType = Integer.parseInt(jsonObject.get("contentType").toString());
        // 是否是管理员
        Boolean isAdmin = Boolean.valueOf(jsonObject.get("isAdmin").toString());
        // 保存消息记录
        ContactAdminChatMessage chatMessage = ContactAdminChatMessage.builder()
            .uuid(UUIDGenerator.getUUID())
            .content(content)
            .contentType(ChatMessageContentType.fromValue(contentType))
            .contactAdminChatRoomUuid(roomId)
            .build();
        if (isAdmin) {
            chatMessage.setSendAdminUuid(sendUserUuid);
            chatMessage.setReceiveUserUuid(receiveUserUuid);
        } else {
            chatMessage.setSendUserUuid(sendUserUuid);
            chatMessage.setReceiveAdminUuid(receiveUserUuid);
        }
        contactAdminChatMessageMapper.insert(chatMessage);
        Map<String, Object> map = BeanUtil.beanToMap(chatMessage);
        map.put("isAdmin",isAdmin);
        map.put("contentType", chatMessage.getContentType().getValue());
        map.put("createTime", DateUtil.format(chatMessage.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
        if (!isAdmin) {
            map.put("sendUserAvatar", userMapper.selectById(sendUserUuid).getAvatar());
        } else {
            // TODO 需要提供管理员头像
            map.put("sendUserAvatar", "https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png");
        }
        try {
            ContactAdminWebSocketEndPoint receiveWebSocketEndPoint = connections.get(receiveUserUuid);
            if (ObjectUtil.isNotEmpty(receiveWebSocketEndPoint)) {
                if (receiveWebSocketEndPoint.roomId.equals(roomId)) {
                    receiveWebSocketEndPoint.session.getBasicRemote()
                        .sendText(JSONUtil.toJsonStr(map));
                }
            }
            // 通知发送者，消息已经发送成功
            ContactAdminWebSocketEndPoint sendWebSocketEndPoint = connections.get(sendUserUuid);
            if (ObjectUtil.isNotEmpty(sendWebSocketEndPoint)) {
                if (sendWebSocketEndPoint.roomId.equals(roomId)) {
                    sendWebSocketEndPoint.session.getBasicRemote()
                        .sendText(JSONUtil.toJsonStr(map));
                }
            }
        } catch (Exception e) {
            throw new BusinessException("系统错误，消息发送失败");
        }
    }
}
